package com.google.cloud.testing.android.lib;

import android.util.Log;

import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.conn.HttpHostConnectException;
import org.apache.http.impl.client.DefaultHttpClient;

import java.net.URI;
import java.net.URLEncoder;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * A set of utility methods used from tests
 */
public class CloudUtils {
    private static final String GET_SCREENSHOT_URL = "http://localhost:6789/cmd/screenshot?file=";
    private static final String FILE_NAME_DELIMITER = "-";
    private static final String IMAGE_TYPE = "jpg";
    private static final String LOG_TAG = "cloud_utils";

    /**
     * Immediately take a screenshot with the given name.
     * @param name The name of the screenshot
     */
    public static void takeScreenshot(String name) {
        String filename = getScreenshotFileName(name);
        takeScreenshotInternal(filename);
    }

    private static class GetScreenshotThread extends Thread {
        private final String filename;

        public GetScreenshotThread(String filename) {
            this.filename = filename;
        }

        @Override
        public void run() {
            takeScreenshotInternal(filename);
        }
    }

    /**
     * Take a screenshot and save it as the specified file name
     *
     * Package protected
     *
     * @param fileName name of file in which to save the screenshot
     */
     static void takeScreenshotToFile(String fileName) {
        GetScreenshotThread screenshotThread = new GetScreenshotThread(fileName);

        screenshotThread.start();
        try {
            screenshotThread.join();
        } catch (InterruptedException e) {
            Log.i(LOG_TAG, "Interrupted trying to take screenshot");
        }
    }

    /**
     * Take a screenshot and save it as the specified file name
     * @param fileName name of file in which to save the screenshot
     */
    private static void takeScreenshotInternal(String fileName) {
        try {
            try {
                // TODO(broughton): Adding a 1 second delay which seems to be just sufficient for
                // making sure the screen is fully rendered
                try { Thread.sleep(1000); } catch (Exception ignore) { }

                HttpClient httpclient = new DefaultHttpClient();
                HttpGet request = new HttpGet();
                URI website = new URI(GET_SCREENSHOT_URL + URLEncoder.encode(fileName + "." + IMAGE_TYPE, "UTF-8"));
                request.setURI(website);

                Log.i(LOG_TAG, "Taking screenshot: " + fileName);
                HttpResponse response = httpclient.execute(request);
                String responseString = convertStreamToString(response.getEntity().getContent());
                Log.i(LOG_TAG, "Captured screenshot: " + responseString);

            } catch (HttpHostConnectException e) {
                Log.i(LOG_TAG, "Not running on virtual device. skipping screenshot");
            }
        } catch(Exception e) {
            Log.e(LOG_TAG, "Exception taking screenshot: " + e.toString());
        }
    }

    private static String lastClassName = "";
    private static String lastMethodName = "";
    private static AtomicInteger counter = new AtomicInteger(0);

    /**
     * Construct a screenshot file name from the specified screenshot name
     *
     * @param screenshotName test's name for this screenshot
     * @return screenshot file name with the following format
     *   <fully qualified class name>-<test method name>-<screenshot name>#<step number>
     */
     static String getScreenshotFileName(String screenshotName) {
        for (StackTraceElement e : Thread.currentThread().getStackTrace()) {
            if (e.getClassName().endsWith("Test") && e.getMethodName().startsWith("test")) {
                if (!e.getClassName().equals(lastClassName) ||
                        !e.getMethodName().equals(lastMethodName)) {
                    counter = new AtomicInteger(0);
                }
                lastClassName = e.getClassName();
                lastMethodName = e.getMethodName();
                String filename = e.getClassName()
                        + FILE_NAME_DELIMITER + e.getMethodName()
                        + FILE_NAME_DELIMITER + screenshotName
                        + FILE_NAME_DELIMITER + counter.incrementAndGet();

                return filename;
            }
        }

        lastClassName = "";
        lastMethodName = "";
        return "SomeTest"
                + FILE_NAME_DELIMITER + "testSomething"
                + FILE_NAME_DELIMITER + screenshotName
                + FILE_NAME_DELIMITER + counter.incrementAndGet();
    }

    private static String convertStreamToString(java.io.InputStream is) {
        java.util.Scanner s = new java.util.Scanner(is).useDelimiter("\\A");
        return s.hasNext() ? s.next() : "";
    }
}

